﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace CNav.Repository.UoV
{
    public interface IRepositoryQuery<TEntity> where TEntity : class
    {
        IList<TEntity> GetPage(int page, int pageSize, out int totalCount);
        IRepositoryQuery<TEntity> Include(Expression<Func<TEntity, object>> expression);
        IRepositoryQuery<TEntity> OrderBy(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy);
        IList<TEntity> ToList();
        IRepositoryQuery<TEntity> Where(Expression<Func<TEntity, bool>> filter);
    }

    public sealed class RepositoryQuery<TEntity> : IRepositoryQuery<TEntity> where TEntity : class
    {
        private readonly List<Expression<Func<TEntity, object>>> includeProperties;

        private readonly Repository<TEntity> repository;
        private Expression<Func<TEntity, bool>> filterFunc;
        private Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderByQuerable;
        private int? pageNumber;
        private int? recordPerPage;

        public RepositoryQuery(Repository<TEntity> repository)
        {
            this.repository = repository;
            includeProperties = new List<Expression<Func<TEntity, object>>>();
        }

        public IRepositoryQuery<TEntity> Where(Expression<Func<TEntity, bool>> filter)
        {
            this.filterFunc = filter;
            return this;
        }

        public IRepositoryQuery<TEntity> OrderBy(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy)
        {
            orderByQuerable = orderBy;
            return this;
        }

        public IRepositoryQuery<TEntity> Include(Expression<Func<TEntity, object>> expression)
        {
            includeProperties.Add(expression);
            return this;
        }

        public IList<TEntity> GetPage(int page, int pageSize, out int totalCount)
        {
            this.pageNumber = page;
            this.recordPerPage = pageSize;
            totalCount = repository.Get(filterFunc).Count();

            return repository.Get(filterFunc, orderByQuerable, includeProperties, this.pageNumber, this.recordPerPage).ToList();
        }

        public IList<TEntity> ToList()
        {
            return repository.Get(filterFunc, orderByQuerable, includeProperties, pageNumber, recordPerPage).ToList();
        }
    }
}